--- ./liblightdm-gobject/language.c.orig	2013-09-25 00:08:16.000000000 +0000
+++ ./liblightdm-gobject/language.c	2014-03-11 21:41:48.000000000 +0000
@@ -8,12 +8,37 @@
  * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
  */
 
+#include <config.h>
+
 #include <string.h>
 #include <locale.h>
 #include <langinfo.h>
 #include <stdio.h>
 #include <glib/gi18n.h>
 
+#ifdef HAVE_ISO_CODES
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <gio/gio.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#if defined(__linux__)
+#define DEFAULT_LOCALE "en_US.utf8"
+#elif defined(__FreeBSD__) || defined(__DragonFly__) 
+#define DEFAULT_LOCALE "en_US.ISO8859-1"
+#endif
+
+const gchar *get_language_from_env (void);
+gchar *build_filename_iso_code (const gchar *domain);
+const gchar *get_country_code (const gchar *locale);
+xmlChar *parse_iso_3166_file (gchar *filename, const gchar *iso_code);
+xmlChar *get_iso_3166_value (gchar *locale);
+xmlChar *parse_iso_639_file (gchar *filename, const gchar *iso_code);
+xmlChar *get_iso_639_value (gchar *locale);
+
+#endif /* HAVE_ISO_CODES */
+
 #include "lightdm/language.h"
 
 enum {
@@ -72,12 +97,12 @@
             if (code[0] == '\0')
                 continue;
 
-            /* Ignore the non-interesting languages */
-            if (strcmp (command, "locale -a") == 0 && !g_strrstr (code, ".utf8"))
-                continue;
-
-            language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
-            languages = g_list_append (languages, language);
+            /* Avoid to add C and POSIX in GList object */
+            if (g_strcmp0 (code, "C") > 1 && g_strcmp0 (code, "POSIX") > 1)
+            {
+                language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
+                languages = g_list_append (languages, language);
+            }
         }
 
         g_strfreev (tokens);
@@ -89,11 +114,13 @@
     have_languages = TRUE;
 }
 
+/*
 static gboolean
 is_utf8 (const gchar *code)
 {
     return g_strrstr (code, ".utf8") || g_strrstr (code, ".UTF-8");
 }
+*/
 
 /* Get a valid locale name that can be passed to setlocale(), so we always can use nl_langinfo() to get language and country names. */
 static gchar *
@@ -104,9 +131,6 @@
     static gchar **avail_locales;
     gint i;
 
-    if (is_utf8 (code))
-        return (gchar *) code;
-
     if ((at = strchr (code, '@')))
         language = g_strndup (code, at - code);
     else
@@ -134,8 +158,6 @@
         for (i = 0; avail_locales[i]; i++)
         {
             gchar *loc = avail_locales[i];
-            if (!g_strrstr (loc, ".utf8"))
-                continue;
             if (g_str_has_prefix (loc, language))
             {
                 locale = g_strdup (loc);
@@ -149,6 +171,224 @@
     return locale;
 }
 
+#ifdef HAVE_ISO_CODES
+const gchar *
+get_language_from_env (void)
+{
+    gchar **env;
+    const gchar *lang;
+    
+    env = g_get_environ ();
+    lang = g_environ_getenv (env, "LANG");
+    
+    g_strfreev (env);
+    
+    if (!lang)
+        /* Define default locale */
+        lang = DEFAULT_LOCALE;
+    else
+        if (g_strcmp0 (lang, "C") == 0 || g_strcmp0 (lang, "POSIX") == 0)
+            /* Replace C or POSIX by default locale */
+            lang = DEFAULT_LOCALE;
+
+    return lang;
+}
+
+gchar *
+build_filename_iso_code (const gchar *domain)
+{
+    gchar *share_dir, *filename;
+    
+    share_dir = g_build_path (G_DIR_SEPARATOR_S, ISO_CODES_PREFIX, "share", NULL);
+    filename = g_build_filename (share_dir, "xml", "iso-codes", domain, NULL);
+    g_free (share_dir);
+    
+    return filename;
+}
+
+/**
+ * get_country_code:
+ *
+ * Return two-letter from locale (e.g en_US.US-ASCII -> US)
+ **/
+const gchar *
+get_country_code (const gchar *locale)
+{
+    gchar **lang_info, **lang_iso;
+    gchar *encoding;
+    const gchar *code = NULL;
+    
+    lang_info = g_strsplit_set (locale , ".@", -1);
+    
+    encoding = g_strdup (lang_info[1]);
+    lang_iso = g_strsplit (g_strdup (lang_info[0]), "_", -1);
+    g_strfreev (lang_info);
+    
+    if (g_strv_length (lang_iso) == 2)
+        code = g_strdup (lang_iso[1]);
+    else
+        code = g_strdup (lang_iso[0]);
+    
+    g_strfreev (lang_iso);
+    
+    if (g_strcmp0 (encoding, "UTF-8") == 0
+        || g_strcmp0 (encoding, "utf8") == 0)
+    {
+        g_free (encoding);
+        
+        return code;
+    }
+    else
+    {
+        g_free (encoding);
+        
+        return g_locale_to_utf8 (code, -1, NULL, NULL, NULL);
+    }
+}
+
+xmlChar *
+parse_iso_3166_file (gchar *filename, const gchar *iso_code)
+{
+    xmlChar *xpath, *res = NULL;
+    
+    xmlDocPtr doc;
+    xmlXPathContextPtr ctx;
+    xmlXPathObjectPtr obj;
+    
+    gchar *str;
+    const gchar *attrib = "name";
+    int size;
+    
+    /* Build dynamic XPath expression */
+    str = g_strdup_printf ("//iso_3166_entry[@alpha_2_code='%s']",
+        g_utf8_strup (iso_code, sizeof (iso_code)));
+    xpath = xmlCharStrdup (str);
+    g_free (str);
+    
+    /* Parse XML file */
+    doc = xmlParseFile (filename);
+    ctx = xmlXPathNewContext (doc);
+    
+    if (ctx == NULL)
+        xmlFreeDoc (doc);
+
+    obj = xmlXPathEvalExpression (xpath, ctx);
+    if (obj == NULL)
+    {
+        printf ("Failed to evaluate XPath expression\n");
+        xmlXPathFreeContext (ctx);
+        xmlFreeDoc (doc);
+    }
+    
+    size = obj->nodesetval->nodeNr;
+    if (size == 1)
+        res = xmlGetProp (obj->nodesetval->nodeTab[0], xmlCharStrdup (attrib));
+    
+    xmlXPathFreeObject (obj);
+    xmlXPathFreeContext (ctx);
+    xmlFreeDoc (doc);
+    
+    return res;
+}
+
+/**
+ * get_iso_3166_value:
+ *
+ * Return real name of country (from iso code)
+ **/
+xmlChar *
+get_iso_3166_value (gchar *locale)
+{
+    const gchar *iso_file = "iso_3166.xml";
+    
+    GFile *file;
+    xmlChar *country = NULL;
+    gchar *src;
+    const gchar *country_code;
+    
+    src = build_filename_iso_code (iso_file);
+    file = g_file_new_for_path (src);
+    
+    if (g_file_query_exists (file, NULL))
+    {
+        g_object_unref (file);
+        
+        country_code = get_country_code (locale);
+        country = parse_iso_3166_file (src, country_code);
+    }
+    
+    return country;
+}
+
+xmlChar *
+parse_iso_639_file (gchar *filename, const gchar *iso_code)
+{
+    xmlChar *xpath, *res = NULL;
+    
+    xmlDocPtr doc;
+    xmlXPathContextPtr ctx;
+    xmlXPathObjectPtr obj;
+    
+    gchar *str;
+    const gchar *attrib = "name";
+    int size;
+    
+    /* Build dynamic XPath expression */
+    str = g_strdup_printf ("//iso_639_entry[@iso_639_1_code='%s']", g_utf8_strdown (iso_code, sizeof (iso_code)));
+    xpath = xmlCharStrdup (str);
+    g_free (str);
+
+    /* Parse XML file */
+    doc = xmlParseFile (filename);
+    ctx = xmlXPathNewContext (doc);
+    
+    if (ctx == NULL)
+        xmlFreeDoc (doc);
+    
+    obj = xmlXPathEvalExpression (xpath, ctx);
+    if (obj == NULL)
+    {
+        printf ("Failed to evaluate XPath expression\n");
+        xmlXPathFreeContext (ctx);
+        xmlFreeDoc (doc);
+    }
+    
+    size = obj->nodesetval->nodeNr;
+    if (size == 1)
+        res = xmlGetProp (obj->nodesetval->nodeTab[0], xmlCharStrdup (attrib));
+    
+    xmlXPathFreeObject (obj);
+    xmlXPathFreeContext (ctx);
+    xmlFreeDoc (doc);
+    
+    return res;
+}
+
+xmlChar *
+get_iso_639_value (gchar *locale)
+{
+    const gchar *iso_file = "iso_639.xml";
+    
+    GFile *file;
+    xmlChar *country = NULL;
+    gchar *src;
+    const gchar *country_code;
+    
+    src = build_filename_iso_code (iso_file);
+    file = g_file_new_for_path (src);
+    
+    if (g_file_query_exists (file, NULL))
+    {
+        g_object_unref (file);
+        
+        country_code = get_country_code (locale);
+        country = parse_iso_639_file (src, country_code);
+    }
+    
+    return country;
+}
+#endif
+
 /**
  * lightdm_get_language:
  *
@@ -162,7 +402,11 @@
     const gchar *lang;
     GList *link;
 
+    #ifdef HAVE_ISO_CODES
+    lang = get_language_from_env ();
+    #else
     lang = g_getenv ("LANG");
+    #endif
     if (!lang)
         return NULL;
 
@@ -228,13 +472,20 @@
         if (locale)
         {
             gchar *current = setlocale (LC_ALL, NULL);
+            
+            #ifdef HAVE_ISO_CODES
+            xmlChar *language_en = get_iso_639_value (priv->code);
+            if (language_en)
+                priv->name = g_strdup (dgettext ("iso_639_3", (gchar *) language_en));
+            #else            
             setlocale (LC_IDENTIFICATION, locale);
             setlocale (LC_MESSAGES, "");
 
             gchar *language_en = nl_langinfo (_NL_IDENTIFICATION_LANGUAGE);
             if (language_en && strlen (language_en) > 0)
                 priv->name = g_strdup (dgettext ("iso_639_3", language_en));
-
+            #endif
+            
             setlocale (LC_ALL, current);
         }
         if (!priv->name)
@@ -271,13 +522,20 @@
         if (locale)
         {
             gchar *current = setlocale (LC_ALL, NULL);
+            
+            #ifdef HAVE_ISO_CODES
+            xmlChar *country_en = get_iso_3166_value (priv->code);
+            if (country_en)
+                priv->territory = g_strdup (dgettext ("iso_3166", (gchar *) country_en));
+            #else
             setlocale (LC_IDENTIFICATION, locale);
             setlocale (LC_MESSAGES, "");
 
             gchar *country_en = nl_langinfo (_NL_IDENTIFICATION_TERRITORY);
             if (country_en && strlen (country_en) > 0 && g_strcmp0 (country_en, "ISO") != 0)
                 priv->territory = g_strdup (dgettext ("iso_3166", country_en));
-
+            #endif
+            
             setlocale (LC_ALL, current);
         }
         if (!priv->territory)
@@ -310,15 +568,6 @@
 
     priv = GET_PRIVATE (language);
 
-    /* Handle the fact the UTF-8 is specified both as '.utf8' and '.UTF-8' */
-    if (is_utf8 (priv->code) && is_utf8 (code))
-    {
-        /* Match the characters before the '.' */
-        int i;
-        for (i = 0; priv->code[i] && code[i] && priv->code[i] == code[i] && code[i] != '.' ; i++);
-        return priv->code[i] == '.' && code[i] == '.';
-    }
-
     return g_str_equal (priv->code, code);
 }
 
